import React, { useState, useEffect } from "react";
import { Avatar, InputProps, SearchBar } from "antd-mobile";
import { AddCircleOutline, MinusCircleOutline, CheckOutline } from "antd-mobile-icons";
import VirtualScroll from "../VirtualScroll";
import { pruneTreeData, searchTreeData, selectTreeData } from "../../utils";
import type { Key, MapTreeDataResult } from "../VirtualScroll";
import styles from "./PortingContainer.less";

const LINE_HEIGHT = 50;

interface PortingContainerProps<T extends Key> {
  value?: T | T[];
  onChange?: (value?: T | T[]) => void;
  withSearch?: boolean;
  searchProps?: InputProps;
  treeData: MapTreeDataResult<T>;
  /** multiple 为true时 有效 */
  showCheckedStrategy?: "SHOW_ALL" | "SHOW_PARENT" | "SHOW_CHILD";
  /** multiple 为true时 有效 */
  treeCheckStrictly?: boolean;
  /** 仅初始化有效 */
  expendKeys?: T[];
  /** 仅初始化有效 */
  expendAll?: boolean;
  /** treeCheckStrictly 为true时 有效 */
  maxCheckedCount?: number;
  multiple?: boolean;
  height?: number;
  /** 二次封装组件时使用 */
  showCheckedOnly?: boolean;
}

export const PortingContainer = function <T extends Key>(props: PortingContainerProps<T>) {
  const { showCheckedStrategy = "SHOW_ALL", treeCheckStrictly = false, maxCheckedCount, showCheckedOnly = false, multiple } = props;
  const [height, setHeight] = useState(props.height || document.documentElement.clientHeight);
  const [clientHeightChange, setClientHeightChange] = useState(0);
  const [keyword, setKeyword] = useState("");
  const [selectedKeys, setSelectedKeys] = useState<T[]>([]);
  const [expendKeys, setExpendKeys] = useState<Set<T>>(new Set(props.expendAll ? props.treeData[1].keys() : props.expendKeys || []));

  /** 需要选中的key */
  useEffect(
    function () {
      if (Array.isArray(props.value)) {
        if (treeCheckStrictly) {
          setSelectedKeys(props.value);
        } else {
          setSelectedKeys(props.value.reduce(selectTreeData(props.treeData), [] as T[]));
        }
      } else if (typeof props.value === "number" || typeof props.value === "string") {
        setSelectedKeys([].concat(props.value));
      }
    },
    [props.value, props.treeData, treeCheckStrictly]
  );

  const onExpend = (key: T, expended: boolean) => (e: React.MouseEvent) => {
    const set = new Set(expendKeys);
    if (!expended) {
      set.delete(key);
    } else {
      set.add(key);
    }
    setExpendKeys(set);
    e.preventDefault();
    e.stopPropagation();
  };

  const onChecked = (key: T, checked: boolean) => () => {
    if (multiple) {
      let keys: T[];
      if (treeCheckStrictly) {
        keys = checked ? selectedKeys.concat(key) : selectedKeys.filter((k) => k != key);
      } else {
        keys = selectTreeData(props.treeData, checked)(selectedKeys, key);
      }
      setSelectedKeys(keys);
      if (props.onChange) {
        switch (showCheckedStrategy) {
          case "SHOW_ALL":
            props.onChange(keys);
            break;
          case "SHOW_CHILD":
            props.onChange(
              keys.filter((k) => {
                const item = props.treeData[1].get(k);
                return !item.children;
              })
            );
            break;
          case "SHOW_PARENT":
            props.onChange(pruneTreeData(props.treeData)(keys));
            break;
        }
      }
    } else {
      setSelectedKeys(checked ? [key] : []);
      props.onChange?.(checked ? key : null);
    }
  };

  const treeData = searchTreeData(
    keyword,
    props.treeData,
    showCheckedOnly
      ? function (item) {
          return (
            selectedKeys?.includes(item.key) ||
            !!selectedKeys.find((k) => {
              const _item = props.treeData[1].get(k);
              return _item.parent_keys.includes(item.key);
            })
          );
        }
      : undefined
  );
  const checkedToMax = maxCheckedCount && selectedKeys?.length >= maxCheckedCount;

  useEffect(function () {
    const clientHeight = document.documentElement.clientHeight;
    setHeight(props.height || clientHeight);
    const resize = function () {
      setClientHeightChange(document.documentElement.clientHeight - clientHeight);
    };
    addEventListener("resize", resize);
    return function () {
      removeEventListener("resize", resize);
    };
  }, []);

  useEffect(
    function () {
      if (props.height) {
        setHeight(props.height);
      }
    },
    [props.height]
  );

  return (
    <div className={styles.tree_container} style={{ height: height + clientHeightChange - 45 }}>
      <SearchBar placeholder="输入关键字过滤, 支持拼音搜索" onSearch={setKeyword} onClear={() => setKeyword("")} />
      <VirtualScroll treeData={treeData} expendKeys={expendKeys} style={{ height: height + clientHeightChange - 75 }}>
        {(item, i, deepth) => {
          const expended = expendKeys.has(item.key);
          const checked = selectedKeys?.includes(item.key);
          const disabled = item?.disabled || (checkedToMax && !checked);
          return (
            <div
              className={`${styles.tree_item} ${checked ? styles.checked : ""} ${disabled ? styles.disabled : ""}`}
              onClick={disabled ? null : onChecked(item.key, !checked)}
            >
              <span
                className={styles.prefix}
                style={{
                  height: LINE_HEIGHT,
                  lineHeight: `${LINE_HEIGHT}px`,
                  paddingLeft: `${deepth + 0.5}rem`,
                }}
                onClick={onExpend(item.key, !expended)}
              >
                {item.children && (expended ? <MinusCircleOutline /> : <AddCircleOutline />)}
              </span>
              {item.title} {item.desc} {checked && <CheckOutline className={styles.checked} />}
            </div>
          );
        }}
      </VirtualScroll>
    </div>
  );
};
